#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include <jsoncpp/json/json.h>
#include "Log.hpp"

using namespace My_Log;

const std::string sep = "\r\n";

bool Encode(std::string &message)
{
    int size = message.size();
    std::string tmp = std::to_string(size) + sep + message + sep;
    message = tmp;
    return true;
}

bool Decode(std::string &package, std::string *message)
{
    int pos = package.find(sep);
    if (pos == std::string::npos)
    {
        return false;
    }

    std::string msglen_str = (package.substr(0, pos));
    int msglen = std::stoi(msglen_str);
    int full_msglen = msglen_str.size() + msglen + 2 * sep.size();
    if (package.size() < full_msglen)
    {
        return false;
    }

    *message = package.substr(pos + sep.size(), msglen);
    package.erase(0, full_msglen);
    return true;
}

class Request
{
public:
    Request(int x = 0, int y = 0, char oper = 0) : _x(x), _y(y), _oper(oper)
    {
    }
    bool Serialize(std::string &out_string)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::StreamWriterBuilder wbuilder;
        std::unique_ptr<Json::StreamWriter> write(wbuilder.newStreamWriter());

        std::stringstream ss;
        write->write(root, &ss);

        out_string = ss.str();
        return true;
    }

    bool Deserialize(std::string &in_string)
    {
        Json::Value root;
        Json::Reader reader;

        bool n = reader.parse(in_string, root);
        if (!n)
        {
            LOG(LogLevel::WARNING) << "Failed to parse JSON: " << reader.getFormattedErrorMessages();
            return false;
        }

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;
    }

    int GetX() const { return _x; }
    int GetY() const { return _y; }
    char GetOper() const { return _oper; }
    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response(int result = 0, int code = 0) : _result(result), _code(code)
    {
    }
    Response(const Response& response)
    {
        _result = response.GetResult();
        _code = response.GetCode();
    }
    bool Serialize(std::string &out_string)
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::StreamWriterBuilder wbuilder;
        std::unique_ptr<Json::StreamWriter> write(wbuilder.newStreamWriter());

        std::stringstream ss;
        write->write(root, &ss);

        out_string = ss.str();
        return true;
    }

    bool Deserialize(std::string &in_string)
    {
        Json::Value root;
        Json::Reader reader;

        bool n = reader.parse(in_string, root);
        if (!n)
        {
            LOG(LogLevel::WARNING) << "Failed to parse JSON: " << reader.getFormattedErrorMessages();
            return false;
        }

        _result = root["result"].asInt();
        _code = root["code"].asInt();
        return true;
    }
    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }
    int GetResult() const { return _result; }
    int GetCode() const { return _code; }
    ~Response() {}

private:
    int _result;
    int _code;
};